﻿using Groove.Core.MediaFile;
using Groove.Core.Player;
using System;
using System.Windows.Forms;

namespace Groove.Winform.Player
{
    public partial class UcPlayer : UserControl
    {
        private IPlayerEngine _player;

        public PlayMode PlayMode { get; private set; } = PlayMode.ListCycle;

        public event EventHandler Next;

        public event EventHandler Previous;

        private IMediaFile _mediaFile;
        public IMediaFile CurrentMediaFile => _mediaFile;

        public UcPlayer()
        {
            InitializeComponent();
            Load += (s, e) =>
            {
                if (ParentForm != null) ParentForm.FormClosing += ParentForm_FormClosing;
            };
            RegistButtonUIEvents();
            RegistControlEvents();
            CheckForIllegalCrossThreadCalls = false;
        }

        private void ParentForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            _player.ShutDown();
        }

        /// <summary>
        /// 设置当前播放媒体文件
        /// </summary>
        /// <param name="file">媒体文件</param>
        /// <param name="startToPlay">是否开始播放</param>
        public void SetCurrentMediaFile(IMediaFile file,bool startToPlay)
        {
            _mediaFile = file;
            ccProgress.MaxValue = (int)file.Duration.TotalMilliseconds;
            lblTitle.Text = file.Title;
            lblArtistAndAlbum.Text = $@"{file.Artists}· {file.Album}";
            _player.CurrentMediaFile = file;
            if (startToPlay)
                _player.PlayOrPause();
        }

        /// <summary>
        /// 初始化播放器引擎
        /// </summary>
        public void InitPlayer()
        {
            _player = new FMODPlayerEngine();
            _player.Init();
            _player.PositionChanged += Player_PositionChanged;
            _player.PlayNext += PlayNext;
            _player.StateChanged += Player_StateChanged;
        }

        private void Player_StateChanged(object sender, EventArgs e)
        {
            SetPlayButtonImage();
            ccProgress.Enabled = _player.PlayerState == PlayerState.Playing;
        }

        private void RegistButtonUIEvents()
        {
            btnPlayAndPause.MouseEnter += (s, e) =>
            {
                SetPlayButtonImage();
            };
            btnPrevious.MouseEnter += (s,e)=>
            {
                btnPrevious.Image = Properties.Resources.PreviousActive;
            };
            btnNext.MouseEnter += (s, e) =>
            {
                btnNext.Image = Properties.Resources.NextActive;
            };
            btnPlaymode.MouseEnter += (s, e) =>
            {
                SetPlaymodeButtonImage();
            };
            btnVolumn.MouseEnter += (s, e) =>
            {
                SetVolumnButtonImage();
            };

            btnPlayAndPause.MouseLeave += (s, e) =>
            {
                SetPlayButtonImage();                
            };
            btnPrevious.MouseLeave += (s, e) =>
            {
                btnPrevious.Image = Properties.Resources.Previous;
            };
            btnNext.MouseLeave += (s, e) =>
            {
                btnNext.Image = Properties.Resources.Next;
            };
            btnPlaymode.MouseLeave += (s, e) =>
            {
                SetPlaymodeButtonImage();
            };
            btnVolumn.MouseLeave += (s, e) =>
            {
                SetVolumnButtonImage();
            };
        }

        private void SetVolumnButtonImage()
        {
            var mp = btnVolumn.PointToClient(MousePosition);
            var isContainMouse = btnVolumn.ClientRectangle.Contains(mp);
            btnVolumn.Image = _player.IsMuted
                ? isContainMouse ? Properties.Resources.MuteActive : Properties.Resources.Mute
                : isContainMouse ? Properties.Resources.VolumActive : Properties.Resources.Volumn;
        }

        private void SetPlaymodeButtonImage()
        {
            var mp = btnPlaymode.PointToClient(MousePosition);
            var isContainMouse = btnPlaymode.ClientRectangle.Contains(mp);
            switch (PlayMode)
            {
                case PlayMode.ListCycle:
                    btnPlaymode.Image = isContainMouse ? Properties.Resources.ListCycleActive : Properties.Resources.ListCycle;
                    break;
                case PlayMode.SingleCycle:
                    btnPlaymode.Image = isContainMouse ? Properties.Resources.SingleCycleActive : Properties.Resources.SingleCycle;
                    break;
                case PlayMode.RandomPlay:
                    btnPlaymode.Image = isContainMouse ? Properties.Resources.RandomPlayActive : Properties.Resources.RandomPlay;
                    break;
            }
        }

        private void SetPlayButtonImage()
        {
            if (btnPlayAndPause.IsDisposed) return;
            var mp = btnPlayAndPause.PointToClient(MousePosition);
            var isContainMouse = btnPlayAndPause.ClientRectangle.Contains(mp);

            btnPlayAndPause.Image = _player.PlayerState == PlayerState.Playing
                ? isContainMouse ? Properties.Resources.PauseActive : Properties.Resources.Pause
                : isContainMouse ? Properties.Resources.PlayActive : Properties.Resources.Play;
        }

        private void RegistControlEvents()
        {
            btnPlayAndPause.Click += BtnPlayAndPause_Click;
            btnPrevious.Click += BtnPrevious_Click;
            btnNext.Click += BtnNext_Click;
            btnPlaymode.Click += BtnPlaymode_Click;
            btnVolumn.Click += BtnVolumn_Click;
            ucVolumnProgress.ValueSelected += UcVolumnProgress_ValueSelected;
            ccProgress.ValueSelected += CCProgress_ValueSelected;
        }

        private void BtnPlayAndPause_Click(object sender, EventArgs e)
        {
            _player.PlayOrPause();
        }

        private void BtnPrevious_Click(object sender, EventArgs e)
        {
            Previous?.Invoke(this, EventArgs.Empty);
        }

        private void BtnNext_Click(object sender, EventArgs e)
        {
            Next?.Invoke(this, EventArgs.Empty);
        }

        private void BtnPlaymode_Click(object sender, EventArgs e)
        {
            switch (PlayMode)
            {
                case PlayMode.ListCycle:
                    PlayMode = PlayMode.SingleCycle;
                    break;
                case PlayMode.SingleCycle:
                    PlayMode = PlayMode.RandomPlay;
                    break;
                case PlayMode.RandomPlay:
                    PlayMode = PlayMode.ListCycle;
                    break;
            }
            SetPlaymodeButtonImage();
        }

        private void BtnVolumn_Click(object sender, EventArgs e)
        {
            SetMute();
        }

        private void UcVolumnProgress_ValueSelected(object sender, EventArgs e)
        {
            var volumn = ucVolumnProgress.Value;
            if (volumn == 0)
                SetMute();
            else
            {
                _player.Volumn = volumn;
                if (_player.IsMuted)
                {
                    _player.Mute();
                    SetVolumnButtonImage();
                }
            }
        }

        private void SetMute()
        {
            _player.Mute();
            SetVolumnButtonImage();
            ucVolumnProgress.Value = _player.IsMuted ? 0 : (int)_player.Volumn;
        }

        private void CCProgress_ValueSelected(object sender, EventArgs e)
        {
            _player.PositionMs = (uint)ccProgress.Value;
        }

        private void Player_PositionChanged(uint currentPosition)
        {
            ccProgress.Value = (int)currentPosition;
            var leftLength = ccProgress.MaxValue - ccProgress.Value;
            var duration = FormatMsToTimeSpan(ccProgress.Value);
            var leftDuration= FormatMsToTimeSpan(leftLength);
            lblCurrentTime.Text = $@"{duration.Minutes:D2}:{duration.Seconds:D2}";
            lblLeftTime.Text = $@"{leftDuration.Minutes:D2}:{leftDuration.Seconds:D2}";
        }

        private void PlayNext(object sender, EventArgs e)
        {
            this.DoInvoke(() =>
            {
                ccProgress.Value = 0;
                ccProgress.Enabled = false;
                if (PlayMode == PlayMode.SingleCycle)
                    _player.PlayOrPause();
                else
                    Next?.Invoke(this, EventArgs.Empty);
            });            
        }

        private TimeSpan FormatMsToTimeSpan(int ms)
        {
            var hour = 0;
            var minute = 0;
            var second = ms / 1000;

            if (second > 60)
            {
                minute = second / 60;
                second %= 60;
            }
            if (minute > 60)
            {
                hour = minute / 60;
                minute %= 60;
            }
            return new TimeSpan(hour, minute, second);
        }        
    }
}
